// yangbuyi Copyright (c) https://yby6.com 2023.

// 定义一个一定时间后自动成功的promise，让调用nextTick方法处，进入下一个then方法
const nextTick = () => new Promise((resolve) => setTimeout(resolve, 1000 / 50));
// nvue动画模块实现细节抽离在外部文件
import animationMap from "./nvue.ani-map.js";

// #ifndef APP-NVUE
// 定义类名，通过给元素动态切换类名，赋予元素一定的css动画样式
const getClassNames = (name) => ({
  enter: `u-${name}-enter u-${name}-enter-active`,
  "enter-to": `u-${name}-enter-to u-${name}-enter-active`,
  leave: `u-${name}-leave u-${name}-leave-active`,
  "leave-to": `u-${name}-leave-to u-${name}-leave-active`,
});
// #endif

// #ifdef APP-NVUE
// 引入nvue(weex)的animation动画模块，文档见：
// https://weex.apache.org/zh/docs/modules/animation.html#transition
const animation = uni.requireNativePlugin("animation");
const getStyle = (name) => animationMap[name];
// #endif

export default {
  methods: {
    // 组件被点击发出事件
    clickHandler() {
      this.$emit("click");
    },
    // #ifndef APP-NVUE
    // vue版本的组件进场处理
    vueEnter() {
      // 动画进入时的类名
      const classNames = getClassNames(this.mode);
      // 定义状态和发出动画进入前事件
      this.status = "enter";
      this.$emit("beforeEnter");
      this.inited = true;
      this.display = true;
      this.classes = classNames.enter;
      this.$nextTick(async () => {
        // #ifdef H5
        await uni.$u.sleep(20);
        // #endif
        // 标识动画尚未结束
        this.$emit("enter");
        this.transitionEnded = false;
        // 组件动画进入后触发的事件
        this.$emit("afterEnter");
        // 赋予组件enter-to类名
        this.classes = classNames["enter-to"];
      });
    },
    // 动画离场处理
    vueLeave() {
      // 如果不是展示状态，无需执行逻辑
      if (!this.display) return;
      const classNames = getClassNames(this.mode);
      // 标记离开状态和发出事件
      this.status = "leave";
      this.$emit("beforeLeave");
      // 获得类名
      this.classes = classNames.leave;

      this.$nextTick(() => {
        // 动画正在离场的状态
        this.transitionEnded = false;
        this.$emit("leave");
        // 组件执行动画，到了执行的执行时间后，执行一些额外处理
        setTimeout(this.onTransitionEnd, this.duration);
        this.classes = classNames["leave-to"];
      });
    },
    // #endif
    // #ifdef APP-NVUE
    // nvue版本动画进场
    nvueEnter() {
      // 获得样式的名称
      const currentStyle = getStyle(this.mode);
      // 组件动画状态和发出事件
      this.status = "enter";
      this.$emit("beforeEnter");
      // 展示生成组件元素
      this.inited = true;
      this.display = true;
      // 在nvue安卓上，由于渲染速度慢，在弹窗，键盘，日历等组件中，渲染其中的内容需要时间
      // 导致出现弹窗卡顿，这里让其一开始为透明状态，等一定时间渲染完成后，再让其隐藏起来，再让其按正常逻辑出现
      this.viewStyle = {
        opacity: 0,
      };
      // 等待弹窗内容渲染完成
      this.$nextTick(() => {
        // 合并样式
        this.viewStyle = currentStyle.enter;
        Promise.resolve()
          .then(nextTick)
          .then(() => {
            // 组件开始进入前的事件
            this.$emit("enter");
            // nvue的transition动画模块需要通过ref调用组件，注意此处的ref不同于vue的this.$refs['u-transition']用法
            animation.transition(
              this.$refs["u-transition"].ref,
              {
                styles: currentStyle["enter-to"],
                duration: this.duration,
                timingFunction: this.timingFunction,
                needLayout: false,
                delay: 0,
              },
              () => {
                // 动画执行完毕，发出事件
                this.$emit("afterEnter");
              }
            );
          })
          .catch(() => {});
      });
    },
    nvueLeave() {
      if (!this.display) {
        return;
      }
      const currentStyle = getStyle(this.mode);
      // 定义状态和事件
      this.status = "leave";
      this.$emit("beforeLeave");
      // 合并样式
      this.viewStyle = currentStyle.leave;
      // 放到promise中处理执行过程
      Promise.resolve()
        .then(nextTick) // 等待几十ms
        .then(() => {
          this.transitionEnded = false;
          // 动画正在离场的状态
          this.$emit("leave");
          animation.transition(
            this.$refs["u-transition"].ref,
            {
              styles: currentStyle["leave-to"],
              duration: this.duration,
              timingFunction: this.timingFunction,
              needLayout: false,
              delay: 0,
            },
            () => {
              this.onTransitionEnd();
            }
          );
        })
        .catch(() => {});
    },
    // #endif
    // 完成过渡后触发
    onTransitionEnd() {
      // 如果已经是结束的状态，无需再处理
      if (this.transitionEnded) return;
      this.transitionEnded = true;
      // 发出组件动画执行后的事件
      this.$emit(this.status === "leave" ? "afterLeave" : "afterEnter");
      if (!this.show && this.display) {
        this.display = false;
        this.inited = false;
      }
    },
  },
};
